package com.enlighten.featureExtractor.coin;

import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;

import com.enlighten.featureExtractor.ICoin;
import com.enlighten.featureExtractor.IRadiusFeatureStrategy;
import com.enlighten.featureExtractor.coinFeature.RadiusBasedCoinFeature;
import com.enlighten.featureExtractor.distances.MeanDsvStdDistance;
import com.enlighten.featureExtractor.exceptions.IncorrectImageSizeException;
import com.enlighten.featureExtractor.radiusFeatureStrategy.SimpleRadiusFeatureStrategy;

public class RadiusBasedCoin implements ICoin<RadiusBasedCoinFeature>{

	private static final int RESOLUTION = 10;
	private int radius;
	
	Map<Integer,RadiusBasedCoinFeature> features;
	IRadiusFeatureStrategy<RadiusBasedCoinFeature> featuresStrategy;

	public RadiusBasedCoin(int width, int height) throws IncorrectImageSizeException {
		if ( width%2 == 0 || height%2 == 0 || width != height )
			throw new IncorrectImageSizeException("Width and Height of image must be odd, and they must be the same");

		this.radius = (width-1) / 2;
		buildFeatures();
	}

	private void buildFeatures() {
		features = new HashMap<Integer, RadiusBasedCoinFeature>();
		featuresStrategy = new SimpleRadiusFeatureStrategy(radius, RESOLUTION);
		while(featuresStrategy.hasNext()){
			RadiusBasedCoinFeature radiusBasedCoinFeature = featuresStrategy.next();
			features.put(radiusBasedCoinFeature.getId(), radiusBasedCoinFeature);
		}
	}

	@Override
	public MeanDsvStdDistance distanceTo(ICoin<RadiusBasedCoinFeature> iCoin) {
		MeanDsvStdDistance meanDsvStdDistance = new MeanDsvStdDistance();
		
		for(Entry<Integer, RadiusBasedCoinFeature> feature:features.entrySet()){
			RadiusBasedCoinFeature model = feature.getValue();
			RadiusBasedCoinFeature sample = iCoin.getFeature(feature.getKey());
			
			if ( sample != null ){
				meanDsvStdDistance.addData(model.distanceTo(sample));
			}
		}
		
		meanDsvStdDistance.calculate();
		return meanDsvStdDistance;
	}

	public void addData(int x, int y, int rgb) {
		int squaredDistanceFromCenter = getSquaredDistanceFromCenter(x,y);
		RadiusBasedCoinFeature radiusBasedCoinFeature = featuresStrategy.getFeatureFor(squaredDistanceFromCenter);
		if ( radiusBasedCoinFeature != null )
			radiusBasedCoinFeature.addPoint(x,y,rgb);
	}

	private int getSquaredDistanceFromCenter(int x, int y) {
		int distX = x-radius;
		int distY = y-radius;
		return distX * distX + distY * distY;
	}

	@Override
	public RadiusBasedCoinFeature getFeature(int featureId) {
		return features.get(featureId);
	}

	@Override
	public String toString() {
		StringBuffer stringBuffer = new StringBuffer();
		stringBuffer.append("{");
		for(Entry<Integer, RadiusBasedCoinFeature> feature:features.entrySet()){
			stringBuffer.append(feature.getKey())
						.append(": ")
						.append(feature.getValue().getDensity())
						.append(" , ");
		}
		stringBuffer.append("}");
		return stringBuffer.toString();
	}
}
